package phase1.part1;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.junit.Before;
import org.junit.Test;

/**
 * 
 * 
 * @author John Girata
 * @version Nov 17, 2012
 */
public class RecursiveDescenderTestCharClasses {
	private CharacterClass chars;
	private CharacterClass digits;
	private CharacterClass printable;

	private RecursiveDescender rd;

	@Before
	public void setup() {
		Map<String, CharacterClass> classes = new HashMap<>();
		digits = new CharacterClass('0', '9');
		classes.put("DIGIT", digits);

		chars = new CharacterClass();
		chars.include('a', 'z');
		chars.include('A', 'Z');
		classes.put("CHAR", chars);

		printable = new CharacterClass(RecursiveDescender.PRINTABLE_START,
				RecursiveDescender.PRINTABLE_END);

		rd = new RecursiveDescender(classes);
	}

	@Test
	public void testCharClass_0() {
		CharacterClass cc = rd.charClass(makeList("$DIGIT"));
		assertEquals(digits, cc);
	}

	@Test
	public void testCharClass_1() {
		CharacterClass cc = rd.charClass(makeList("."));
		assertEquals(printable, cc);
	}

	@Test
	public void testCharClass_2() {
		CharacterClass cc = rd.charClass(makeList("[0-9]"));
		assertEquals(digits, cc);
	}

	@Test
	public void testCharClass_3() {
		CharacterClass cc = rd.charClass(makeList("[^0] IN $DIGIT"));

		assertFalse(cc.contains('0'));
		assertTrue(cc.contains('1'));
		assertTrue(cc.contains('2'));
		assertTrue(cc.contains('3'));
		assertTrue(cc.contains('4'));
		assertTrue(cc.contains('5'));
		assertTrue(cc.contains('6'));
		assertTrue(cc.contains('7'));
		assertTrue(cc.contains('8'));
		assertTrue(cc.contains('9'));
	}
	
	@Test
	public void testCharClass_4() {
		CharacterClass cc = rd.charClass(makeList("[a-ce-g]"));

		assertTrue(cc.contains('a'));
		assertTrue(cc.contains('b'));
		assertTrue(cc.contains('c'));
		assertFalse(cc.contains('d'));
		assertTrue(cc.contains('e'));
		assertTrue(cc.contains('f'));
		assertTrue(cc.contains('g'));
		assertFalse(cc.contains('h'));
	}

	@Test
	public void testCharSet_0() {
		CharacterClass cc = rd.charSetList(makeList("abcd]"),
				new CharacterClass());

		assertTrue(cc.contains('a'));
		assertTrue(cc.contains('b'));
		assertTrue(cc.contains('c'));
		assertTrue(cc.contains('d'));
		assertFalse(cc.contains('e'));
	}

	@Test
	public void testCharSet_1() {
		CharacterClass cc = rd.charSetList(makeList("abcde]"),
				new CharacterClass());

		assertTrue(cc.contains('a'));
		assertTrue(cc.contains('b'));
		assertTrue(cc.contains('c'));
		assertTrue(cc.contains('d'));
		assertTrue(cc.contains('e'));
		assertFalse(cc.contains('f'));
	}

	@Test
	public void testCharSet_2() {
		CharacterClass cc = rd
				.charSetList(makeList("a]"), new CharacterClass());

		assertTrue(cc.contains('a'));
		assertFalse(cc.contains('b'));
	}

	@Test
	public void testExcludeSet() {
		CharacterClass nonZero = rd.excludeSet(makeList("^0] IN $DIGIT"));

		assertFalse(nonZero.contains('0'));
		assertTrue(nonZero.contains('1'));
		assertTrue(nonZero.contains('2'));
		assertTrue(nonZero.contains('3'));
		assertTrue(nonZero.contains('4'));
		assertTrue(nonZero.contains('5'));
		assertTrue(nonZero.contains('6'));
		assertTrue(nonZero.contains('7'));
		assertTrue(nonZero.contains('8'));
		assertTrue(nonZero.contains('9'));
	}

	@Test
	public void testExcludeSetTail_0() {
		CharacterClass cc = rd.excludeSetTail(makeList("[abcde]"));

		assertTrue(cc.contains('a'));
		assertTrue(cc.contains('b'));
		assertTrue(cc.contains('c'));
		assertTrue(cc.contains('d'));
		assertTrue(cc.contains('e'));
		assertFalse(cc.contains('f'));
	}

	private List<Character> makeList(String letters) {
		List<Character> list = new LinkedList<>();

		for (char c : letters.toCharArray()) {
			if (c >= RecursiveDescender.PRINTABLE_START
					&& c <= RecursiveDescender.PRINTABLE_END) {
				list.add(c);
			}
		}

		return list;
	}
}
